#include "device.h"
#include "component.h"
#include "wifi.h"

#define WIFI_LOG(format, ...) OSAL_LOG(C_PURPLE format C_NONE, ##__VA_ARGS__) 

#define EVENT_WIFI_RECONNET  0x00000001

#define WIFI_RECONNECT_MAX_TIMES  9   //最多重连9次

/* WIFI组件NV数据结构 */
typedef struct
{
    uint8_t mac[6];                   //WiFi-MAC
    WifiConnectPara_stu_t conn_param; //WIFI连接参数（如果永久关闭WIFI，就把这个参数清掉）
    WifiApInfo_stu_t ap_info;         //WIFI-AP INFO
    uint32_t init_flag;               //NV初始化标志
}WiFiNv_stu_t;

static TimerHandle_stu_t reconnect_timer = NULL;
static SuperQueueHandle_t wifi_queue = NULL;
static WiFiNv_stu_t wifi_nv;
static WiFiNv_stu_t wifi_nv_tmp;
static uint8_t reconnect_count = 1;   //重连计数（重连间隔为：2^reconnect_count分钟）
static uint8_t wifi_low_power_flag =0;//低电量关闭wifi标志



static void WiFiComp_AutoReconnectTimer(TimerHandle_stu_t t)
{
    WIFI_LOG("auto reconnect...\r\n");
    reconnect_count++;
    reconnect_timer = NULL;
    OSAL_EventSingleCreate(COMP_WIFI, EVENT_WIFI_RECONNET, 0, EVT_PRIORITY_MEDIUM);
}

/**
  * @brief  启动WIFI自动重连
  * 
  */
static void WiFiComp_AutoReconnect(FunctionalState ctrl)
{
    if (ctrl == ENABLE)
    {
        WifiConnectPara_stu_t tmp_conn_param;

        memcpy(&tmp_conn_param, &wifi_nv.conn_param, sizeof(tmp_conn_param));
        OSAL_NvRead(0, &wifi_nv, sizeof(wifi_nv));

        if (strlen(wifi_nv.conn_param.ssid) > 0 && reconnect_count <= WIFI_RECONNECT_MAX_TIMES)
        {
            uint16_t seconds;
            if (memcmp(&tmp_conn_param, &wifi_nv.conn_param, sizeof(tmp_conn_param)) != 0)
            {
                seconds = 1; // 当前连接的SSID与NV存储的SSID不一致时，设定1s后重连NV里面存储的SSID
            }
            else
            {
                seconds = (1 << reconnect_count) * 60;
            }
            reconnect_timer = OSAL_TimerCreate(WiFiComp_AutoReconnectTimer, seconds * 1000, RESET);
            WIFI_LOG("%d seconds later, auto reconnect ap, ssid: %s, pwd: %s\r\n", seconds, wifi_nv.conn_param.ssid, wifi_nv.conn_param.pwd);
        }
    }
    else
    {
        if (reconnect_timer != NULL)
        {
            OSAL_TimerDelete(reconnect_timer);
            reconnect_timer = NULL;
        }
    }
}

/**
  * @brief  WIFI中断处理
  * @note   将wifi底层抛上来的数据缓存至队列
  * @return 
  */
static void WiFiComp_IrqHandler(VirtualHardware_enum_t dev, void *pBuf, uint32_t len)
{   
    uint16_t type = len >> 16;
    uint16_t lenght = (len & 0xFFFF);
    WifiMsg_t *msg = (WifiMsg_t *)OSAL_Malloc(lenght + 1);

    if (msg == NULL)
    {
        return;
    }

    //< 数据缓存至队列
    memset(msg, 0, lenght + 1);
    msg->msg_type = type;
    memcpy(&(msg->ap_list), pBuf, lenght);
    if (OSAL_QueueSendToBack(wifi_queue, msg, lenght + 1) == SUCCESS)
    {
        OSAL_EventCreateFromISR(COMP_WIFI);
    }
    OSAL_Free(msg);
}

/**
  * @brief  处理wifi底层上报的数据
  * @note
  * @return 
  */
static void WiFiComp_ParseRxPacket(void)
{
    uint16_t len;

    while (OSAL_QueueLenght(wifi_queue, &len) > 0)
    {
        WifiMsg_t *packet = (WifiMsg_t *)OSAL_Malloc(len);
        if (packet != NULL)
        {
            memset(packet, 0, len);
            len = OSAL_QueueReceive(wifi_queue, packet);

            WIFI_LOG("wifi event: %d\r\n", packet->msg_type);
            if (packet->msg_type == WIFI_MSG_CONNECTED)
            {
                //< wifi连接成功：AP信息保存至NV
                memcpy(&wifi_nv.ap_info, &(packet->ap_info), sizeof(WifiApInfo_stu_t));
                OSAL_NvWrite(OSAL_OFFSET(WiFiNv_stu_t, ap_info), &wifi_nv.ap_info, sizeof(WifiApInfo_stu_t));
                #ifdef PROJECT_WFP_F
                memcpy(&wifi_nv.conn_param,&wifi_nv_tmp.conn_param,sizeof(WifiConnectPara_stu_t));
                #endif
                OSAL_NvWrite(OSAL_OFFSET(WiFiNv_stu_t, conn_param), &wifi_nv.conn_param, sizeof(WifiConnectPara_stu_t));

                //< WIFI连上了，关闭自动重连TIMER
                WiFiComp_AutoReconnect(DISABLE);
            }
            else if (packet->msg_type == WIFI_MSG_JOIN_FAIL)
            {
                //< 执行connect失败、重新读取NV里面的SSID（上次连接成功的SSID）使能自动重连
                WiFiComp_AutoReconnect(ENABLE);
            }
            else if (packet->msg_type == WIFI_MSG_DISCONNECTED)
            {
                //< 从连接状态变成了断开状态：使能自动重连TIMER
                if (wifi_low_power_flag == 0)
                {
                    WiFiComp_AutoReconnect(ENABLE);
                }
                else
                {
                    WIFI_LOG("wifi_low_power_flag =1\r\n");
                }
                OSAL_EventDelete(COMP_WIFI, EVENT_WIFI_RECONNET);
            }
            OSAL_MessagePublish(packet, len);
            OSAL_Free(packet);
            OSAL_SetTaskStatus(TASK_STA_NORMAL);
        }
    }
}

/**
  * @brief  快速连接
  * 
  * @param  connect：连接的路由信息
  * @param  ap_info：详细信息
  */
static void WiFiComp_FastConnect(WifiConnectPara_stu_t *connect, WifiApInfo_stu_t *ap_info)
{
    /* 3190和C3搞个NULL直接干下去就表示快连 
     * 新做的wifi方案必须在组件存储AP信息，干个NULL下去不会有任何反应
     */
    Device_Write(vWIFI_0, NULL, 0, WIFI_CTRL_CONNECT);

    /* 新做的WiFi方案用参数 “WIFI_CTRL_CONNECT_FAST” 表示快连 */
    if (strlen(connect->ssid) > 0)
    {
        int32_t res =1;
        WifiFastConnectPara_stu_t fast_param;
        memcpy(&fast_param.connect, connect, sizeof(WifiConnectPara_stu_t));
        memcpy(&fast_param.ap, ap_info, sizeof(WifiApInfo_stu_t));
        res = Device_Write(vWIFI_0, &fast_param, sizeof(fast_param), WIFI_CTRL_CONNECT_FAST);
        if(res == 0)
        {
            OSAL_SetTaskStatus(TASK_STA_ACTIVE);
            WIFI_LOG("Set wifi task active\r\n");
        }
    }
    
    /* 停止自动连接 */
    WiFiComp_AutoReconnect(DISABLE);
}

/**
  * @brief  连接WIFI
  * 
  * @param  connect：连接的路由信息
  */
static void WiFiComp_Connect(WifiConnectPara_stu_t *connect)
{
    int32_t res =1;
    /* 暂存应用层下发的SSID，连接成功会保存至NV里 */
    wifi_nv.conn_param = *connect;
    WIFI_LOG("SSID :%s, PWD:%s\r\n",connect->ssid,connect->pwd);

    /* 连接AP */
    res = Device_Write(vWIFI_0, connect, sizeof(WifiConnectPara_stu_t), WIFI_CTRL_CONNECT);
    if(res == 0)
    {
        /* 停止自动连接 */
        WiFiComp_AutoReconnect(DISABLE);

        OSAL_SetTaskStatus(TASK_STA_ACTIVE);
        WIFI_LOG("Set wifi task active\r\n");
    }

    #ifdef PROJECT_WFP_F
    memset(&wifi_nv.conn_param,0,sizeof(WifiConnectPara_stu_t));
    memset(&wifi_nv_tmp.conn_param,0,sizeof(WifiConnectPara_stu_t));
    memcpy(&wifi_nv_tmp.conn_param,connect,sizeof(WifiConnectPara_stu_t)); 
    //< wifi连接成功：AP信息保存至NV
    OSAL_NvWrite(OSAL_OFFSET(WiFiNv_stu_t, conn_param), &wifi_nv.conn_param, sizeof(WifiConnectPara_stu_t));
    #endif
}

/**
  * @brief  断开WIFI连接
  * 
  * @param  0：永久关闭WIFI
  *         1：关闭WIFI，进入间隔重连逻辑（应用层发现mqtt离线了，会发这参数下来）
  */
static void WiFiComp_Disconnect(uint32_t param)
{
    int rc = Device_Write(vWIFI_0, (void *)param, 1, WIFI_CTRL_DISCONNECT);

    if (param == 0)
    {
        memset(&wifi_nv.conn_param, 0, sizeof(WifiConnectPara_stu_t));
        OSAL_NvWrite(OSAL_OFFSET(WiFiNv_stu_t, conn_param), &wifi_nv.conn_param, sizeof(WifiConnectPara_stu_t));
    }
    else
    {
        if (rc == -1 && wifi_low_power_flag == 0)
        {
            WiFiComp_AutoReconnect(ENABLE);
        }
    }
}

/**
  * @brief  处理邮箱发来的数据
  * 
  * @note
  */
static void WiFiComp_ProcessMbox(uint8_t *msg)
{
    switch (msg[0])
    {
    case WIFI_CTRL_CONNECT:    //< 连接WiFi
        WiFiComp_Connect((WifiConnectPara_stu_t*)(&msg[1]));
        break;

    case WIFI_CTRL_DISCONNECT: //< 断开WiFi
        WiFiComp_Disconnect(msg[1]);
        break;

    case WIFI_CTRL_SCAN:       //< 扫描WiFi
        Device_Write(vWIFI_0, NULL, 0, WIFI_CTRL_SCAN);
        break;

    case WIFI_CTRL_RESET_RECONNECT://< 复位自动重连间隔
        reconnect_count = 1;
        break;
    case WIFI_CTRL_DISENABLE://关闭WIFI 不清除SSID
        {
            uint32_t param =0;
            wifi_low_power_flag = 1;
            Device_Write(vWIFI_0,&param, sizeof(param), WIFI_CTRL_DISCONNECT);
        }
        break;
    }
}

/**
  * @brief  Wifi接收邮箱
  *
  * @return NONE
  */
static void WiFiComp_RecvMbox(void)
{
    uint16_t size = 0;
    while (OSAL_MboxLenght(&size) > 0)
    {
        void *buffer = OSAL_Malloc(size);
        if (buffer != NULL)
        {
            memset(buffer, 0, size);
            OSAL_MboxAccept(buffer);
            WiFiComp_ProcessMbox((uint8_t *)buffer);
            OSAL_Free(buffer);
        }
        else
        {
            WIFI_LOG("malloc error\r\n");
        }
    }
}

/**
  * @brief  wifi初始化
  * @note   
  * @return 
  */
static void WiFiComp_Init(void)
{
    /* 读取NV内容 */
    OSAL_NvRead(0, &wifi_nv, sizeof(wifi_nv));
    #ifdef PROJECT_WFP_F
    memset(&wifi_nv_tmp,0,sizeof(wifi_nv_tmp));
    memcpy(&wifi_nv_tmp.conn_param,&wifi_nv.conn_param,sizeof(wifi_nv.conn_param));
    #endif
    if (wifi_nv.init_flag != UINT32_FLAG)
    {
        memset(&wifi_nv, 0, sizeof(wifi_nv));
        wifi_nv.init_flag = UINT32_FLAG;
        Device_Read(vWIFI_0, wifi_nv.mac, 0, 0);
        OSAL_NvWrite(0, &wifi_nv, sizeof(wifi_nv));
        WIFI_LOG("WiFi nv init\r\n");
    }
    WIFI_LOG("WiFi MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n", 
    wifi_nv.mac[0], wifi_nv.mac[1], wifi_nv.mac[2], wifi_nv.mac[3], wifi_nv.mac[4], wifi_nv.mac[5]);

    /* 创建队列、注册中断回调 */
    if (wifi_queue == NULL)
    {
        wifi_queue = OSAL_QueueCreate(20);          
        Device_RegisteredCB(vWIFI_0, WiFiComp_IrqHandler);

    #if 0 //< 测试用：写死SSID
        WifiConnectPara_stu_t test = {
            .ssid = "NETGEAR3389",
            .pwd = "12345678"
            // .ssid = "HUAWEI-A8FF",
            // .pwd = "62020483"
            // .ssid = "NETGEAR09",
            // .pwd = "kds12345678"
            // .ssid = "NETGEAR40",
            // .pwd = "kds666666"
            // .ssid = "test_test",
            // .pwd = "12345678"
            // .ssid = "dxtcyf2.4",
            // .pwd = "dxtc668"
            // .ssid = "NETGEAR85",
            // .pwd = "dxtc_123456"
        };
        WiFiComp_Connect(&test);
        return;
    #endif
    }

    /* 每次唤醒执行WIFI快连 */
    if (OSAL_TimerGetRemaining(reconnect_timer) != 0)
    {
        OSAL_EventSingleCreate(COMP_WIFI, EVENT_WIFI_RECONNET, 300, EVT_PRIORITY_MEDIUM);
    }
}

/**
  * @brief  Wifi任务函数
  *
  * @note
  *
  * @param  event：当前任务的所有事件
  *
  * @return 返回未处理的事件
  */
static uint32_t Wifi_Task(uint32_t event)
{
    /* 系统启动事件 */
    if (event & EVENT_SYS_START)
    {
        WIFI_LOG("wifi task start\r\n");
        WiFiComp_Init();
        Device_Enable(vWIFI_0);
        return (event ^ EVENT_SYS_START);
    }

    /* 系统邮箱事件 */
    if (event & EVENT_SYS_MBOX)
    {   
        WiFiComp_RecvMbox();
        return ( event ^ EVENT_SYS_MBOX );
    }

    /* wifi中断事件 */
    if (event & EVENT_SYS_ISR)
    {
        WIFI_LOG("wifi isr event");
        WiFiComp_ParseRxPacket();
        return (event ^ EVENT_SYS_ISR);
    }

    /* wifi重连事件 */
    if (event & EVENT_WIFI_RECONNET)
    {
        if (wifi_low_power_flag == 0)
        {
            WiFiComp_FastConnect(&wifi_nv.conn_param, &wifi_nv.ap_info);
        }
        return (event ^ EVENT_WIFI_RECONNET);
    }

    /* wifi休眠事件 */
    if (event & EVENT_SYS_SLEEP)
    {
        WIFI_LOG("wifi task sleep\r\n");
        Device_Disable(vWIFI_0);
        return (event ^ EVENT_SYS_SLEEP);
    }
    return 0;
}
COMPONENT_TASK_EXPORT(COMP_WIFI, Wifi_Task, sizeof(WiFiNv_stu_t));

char import_kos_wifi;
